<?php
include_once 'crypto/wxBizMsgCrypt.php';

abstract class WeChatApi {
    public function create(){
        return new static();
    }
    
    /**
     * 微信公众号平台消息鉴权
     */
    public function valid(){
        $echoStr = $_GET['echostr'];
        if($this->checkSignature()){
            echo $echoStr;
            exit;
        }
    }
    
    /**
     * 处理请求并响应
     */
    public function responseMsg(){
        #$postStr = $GLOBALS['HTTP_RAW_POST_DATA'];
        $postStr = file_get_contents("php://input");
        $this->writeLog("\n获取到请求:\n" . $postStr . "\n");
        if (!empty($postStr)){
            // 获取报文传送方式
            $cryptType = isset($_GET['encrypt_type']) ? $_GET['encrypt_type'] : 'none';
            switch($cryptType){
                case 'none':
                case 'raw': // 明文模式
                    $this->writeLog("\n请求明文：\n" . $postStr ."\n");
                    $resultStr = $this->noneEncrypt($postStr);
                    $this->writeLog("\n响应请求：\n" . $resultStr ."\n");
                    break;
                case 'aes': // 兼容 模式 / 安全模式
                    // 解密
                    $msg_sig = $_GET['msg_signature'];
                    $timestp = $_GET['timestamp'];
                    $noc = $_GET['nonce'];
                    
                    $decrMsg = '';
                    $cryptObj = new WXBizMsgCrypt(static::$m_token, static::$m_aes_key, static::$m_appid);
                    $errCode = $cryptObj->decryptMsg($msg_sig, $timestp, $noc, $postStr, $decrMsg);

                    if(0 != $errCode){
                        $this->writeLog("\n $errCode \n");
                        echo '';
                        return ;
                    }
                    
                    $this->writeLog("\n请求明文：\n" . $decrMsg ."\n");
                    // 明文逻辑处理
                    $resultStr = $this->noneEncrypt($decrMsg);
                    $this->writeLog("\n响应请求：\n" . $resultStr ."\n");
                    
                    // 取应答的时间戳
                    libxml_disable_entity_loader(true);
                    $timestp = simplexml_load_string($resultStr, 'SimpleXMLElement', LIBXML_NOCDATA)->CreateTime;
                    
                    // 加密处理
                    $encryptMsg = '';
                    $errCode = $cryptObj->encryptMsg($resultStr, $timestp, $noc, $encryptMsg);
                    $resultStr = $encryptMsg;
                    
                    if(0 != $errCode){
                        echo '';
                        return ;
                    }
                    break;
                default:
                    echo '';
                    return ;
            }            
            echo $resultStr;
        } else {
            echo '';
        }
    }
    
    /**
     * 明文方式处理函数
     */
    protected function noneEncrypt($object){
        if (empty($object)){
            return '';
        }
        
        libxml_disable_entity_loader(true);
        $postObj = simplexml_load_string($object, 'SimpleXMLElement', LIBXML_NOCDATA);
        $tx_type = trim($postObj->MsgType);
        
        switch($tx_type){
            case 'text':
                $resultStr = static::receiveText($postObj);
                break;
            case 'image':
                $resultStr = static::receiveImage($postObj);
                break;
            case 'location':
                $resultStr = static::receiveLocation($postObj);
                break;
            case 'voice':
                $resultStr = static::receiveVoice($postObj);
                break;
            case 'video':
                $resultStr = static::receiveVideo($postObj);
                break;
            case 'link':
                $resultStr = static::receiveLink($postObj);
                break;
            case 'event':
                $resultStr = static::receiveEvent($postObj);
                break;
            default:
                $resultStr = '';    // 直接回复空串,公众号平台将忽略用户的请求
                break;
        }
        
        return $resultStr;
    }
    
    /**
     * @todo : 微信公众平台要求鉴权算法
     */
    protected function checkSignature(){   
        $signature = $_GET['signature'];
        $timestamp = $_GET['timestamp'];
        $nonce = $_GET['nonce'];
    
        $token = static::$m_token;
        $tmpArr = array($token, $timestamp, $nonce);

        sort($tmpArr, SORT_STRING);
        $tmpStr = implode( $tmpArr );
        $tmpStr = sha1( $tmpStr );
    
        if( $tmpStr == $signature ){
            return true;
        }else{
            return false;
        }
    }
    
    /**
     * @todo : 请求平台接口
     * @param $reqType : key关键字,匹配请求的目的url
     * @param $reqMethod : post / get
     * @param $reqParam : 请求参数k-v对
     */
    protected function sendRequest2Plat($reqType, $reqMethod, $reqParam){
        ;
    }
    
    
    /**
     * 转发消息到指定客服
     */
    protected static function transmit2Custom($object, $customerID){
        $textTpl = '<xml>'
                    . '<ToUserName><![CDATA[' . $object->FromUserName . ']]></ToUserName>'
                    . '<FromUserName><![CDATA[' . $object->ToUserName . ']]></FromUserName>'
                    . '<CreateTime>' . time() . '</CreateTime>'
                    . '<MsgType><![CDATA[transfer_customer_service]]></MsgType>'
                    . '<TransInfo><KfAccount><![CDATA[' . $customerID . ']]</KfAccount></TransInfo>'
                  .'</xml>';
        return $textTpl;
    }
    
    
    /**
     * 回复文本消息格式
     */
    protected function transmitText($object, $content){
        $textTpl = '<xml>'
                    . '<ToUserName><![CDATA[' . $object->FromUserName . ']]></ToUserName>'
                    . '<FromUserName><![CDATA[' . $object->ToUserName . ']]></FromUserName>'
                    . '<CreateTime>' . time() . '</CreateTime>'
                    . '<MsgType><![CDATA[text]]></MsgType>'
                    . '<Content><![CDATA[' . $content  . ']]></Content>'
                 . '</xml>';
        return $textTpl;
    }
    
    /**
     * 回复图片消息
     */
    protected function transmitPic($object, $mediaId){
        $textTpl = '<xml>'
                    . '<ToUserName><![CDATA[' . $object->FromUserName . ']]></ToUserName>'
                    . '<FromUserName><![CDATA[' . $object->ToUserName . ']]></FromUserName>'
                    . '<CreateTime>' . time() . '</CreateTime>'
                    . '<MsgType><![CDATA[image]]></MsgType>'
                    . '<Image><MediaId><![CDATA[' . $mediaId .']]></MediaId></Image>'
                 . '</xml>';
        return $textTpl;
    }
    
    /**
     * 回复图文消息：目前最大支持10条消息
     */
    protected function transmitPicText($object, $aryItems){
        $textTpl = '<xml>'
                    . '<ToUserName><![CDATA[' . $object->FromUserName . ']]></ToUserName>'
                    . '<FromUserName><![CDATA[' . $object->ToUserName . ']]></FromUserName>'
                    . '<CreateTime>' . time() . '</CreateTime>'
                    . '<MsgType><![CDATA[news]]></MsgType>'
                    . '<ArticleCount>' . count($aryItems) . '</ArticleCount>'
                    . '<Articles>';
        foreach ($aryItems as $idx => $aryValue){
            $textTpl .= '<item>'
                        . '<Title><![CDATA[' . $aryValue['title'] . ']]></Title>'
                        . '<Description><![CDATA[' . $aryValue['description'] . ']]></Description>'
                        . '<PicUrl><![CDATA[' . $aryValue['picurl'] . ']]></PicUrl>'
                        . '<Url><![CDATA[' .  $aryValue['url'] . ']]></Url>'
                        .'</item>';
        }
        $textTpl .= '</Articles></xml>';
        return $textTpl;
    }
    

    
    
    /**
     * 处理各消息类型接口, 公众号可根据业务需要实现感兴趣的消息
     */
    protected function receiveText($object){
        return '';
    }
    
    protected function receiveImage($object){
        return '';
    }
    
    protected function receiveLocation($object){
        return '';
    }
    
    protected function receiveVoice($object){
        return '';
    }
    
    protected function receiveVideo($object){
        return '';
    }
    
    protected function receiveLink($object){
        return '';
    }
    
    protected function receiveEvent($object){
        return '';
    }
    
    
    /**
     * 个人调测代码函数
     */
    public function writeLog($content){
        if(DEBUG_LOG){
            $fp = fopen('/tmp/weChat.log','a');
            if(!$fp){
                return ;
            }
            fwrite($fp, $content);
            fclose($fp);
        }
    }

    /***************************************************
     * 获取用户信息
     ***************************************************/
    #获取access_token
    public function getAccessToken($appid, $secret){
        $request_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$secret;
        $result = $this->get_curl($request_url);
        return $result;
    }


    #获取用户信息
    public function getUserInfo($access_token,$openid){
        $request_url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=".$access_token."&openid=".$openid."&lang=zh_CN";
        $result = $this->get_curl($request_url);
        return $result;
    }


    public function get_curl($url){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        $result_json = curl_exec($ch);
        curl_close($ch);
        return  json_decode($result_json, true);
    }

    function _log_result($logstr, $filename = 'log.txt') {
        $log_dir = "/data/bak/log/";
        $fp = fopen($log_dir . $filename,"a");
        flock($fp, LOCK_EX) ;
        fwrite($fp,"执行日期：".strftime("%Y%m%d%H%M%S",time()).": \n".$logstr."\n");
        flock($fp, LOCK_UN);
        fclose($fp);
    }
}
?>